﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Cysharp.Threading.Tasks;
using GraphProcessor;
using IQIGame.Onigao.GameAOT;
using IQIGame.Onigao.Logic;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace IQIGame.Onigao.GamePlay.Editors
{
    [CustomPropertyDrawer(typeof(LevelServiceEditorCustomPropertyAttribute))]
    public class LevelServiceEditorPropertyDrawer : PropertyDrawer
    {
        // 展示转值
        private Dictionary<string, object> showToValue = new Dictionary<string, object>();
        private List<string> showStr = new List<string>();
        private bool pickBtn;

        private LevelServiceEditorCustomPropertyAttribute customAttr;

        // 若显示内容根据其他参数决定，记录参数判断是否条件参数修改 ,每帧刷新
        private object customAttrCond;

        private bool tableInitialing = false;

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            if (this.customAttr == null)
            {
                this.customAttr = (LevelServiceEditorCustomPropertyAttribute)this.fieldInfo.GetCustomAttribute(typeof(LevelServiceEditorCustomPropertyAttribute), false);
            }

            this.InitializeValueDict(this.customAttr, property);
            if (this.showStr.Count > 0)
            {
                EditorGUILayout.BeginHorizontal(GUILayout.Height(20));
                EditorGUILayout.LabelField(this.customAttr.displayName);
                EditorGUILayout.EndHorizontal();
                string rSelectValue = string.Empty;
                if (property.propertyType == SerializedPropertyType.String)
                {
                    rSelectValue = property.stringValue;
                }
                else if (property.propertyType == SerializedPropertyType.Integer)
                {
                    rSelectValue = this.GetValueName(property.longValue);
                }
                var rDropStr = rSelectValue;
                EditorGUILayout.BeginHorizontal(GUILayout.Height(20));
                var rSettingConfig = LevelServiceEditorSettingGlobal.GetConfig(this.customAttr.key);
                if ((rSettingConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.InputStr) > 0)
                {
                    property.stringValue = EditorGUILayout.TextField(rSelectValue);
                    rDropStr = "";
                }
                if ((rSettingConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.InputInt) > 0)
                {
                    property.longValue = EditorGUILayout.IntField((int)property.longValue);
                    rDropStr = "";
                }
                var rDropdownBtn = EditorGUILayout.DropdownButton(new GUIContent(rDropStr), FocusType.Passive);
                EditorGUILayout.EndHorizontal();
                if (rDropdownBtn)
                {
                    Rect popupRect = EditorGUI.IndentedRect(position);
                    popupRect.x += popupRect.width;
                    popupRect.y += popupRect.height;
                    popupRect.width = 200;
                    // var rShowToLong = new Dictionary<string, long>(this.showToLong);
                    var rShowToValue = new Dictionary<string, object>(this.showToValue);
                    SearchPopupWindow.Create(popupRect, this.showStr, rSelectValue, (x) =>
                    {
                        if (rShowToValue.TryGetValue(x, out var rValue))
                        {
                            switch (property.propertyType)
                            {
                                case SerializedPropertyType.Integer:
                                    var rValueType = rValue.GetType();
                                    if (rValueType == typeof(int))
                                    {
                                        property.longValue = (int)rValue;
                                    }
                                    else if (rValueType == typeof(long))
                                    {
                                        property.longValue = (long)rValue;
                                    }
                                    break;
                                case SerializedPropertyType.String:
                                    property.stringValue = (string)rValue;
                                    break;
                            }
                        }
                        else
                        {
                            property.stringValue = x;
                        }
                        property.serializedObject.ApplyModifiedProperties();
                        LevelServiceBaseNodeView.OnPropertyChange(property.serializedObject);
                    });
                }
            }
            else
            {
                EditorGUILayout.PropertyField(property, new GUIContent(this.customAttr.displayName));
            }
            if (this.pickBtn)
            {
                var rPropertyPath = property.propertyPath;
                bool bAllreadynPacking = LevelServiceBlackboard.Instance.inPicking == rPropertyPath;
                if (bAllreadynPacking)
                {
                    GUI.color = Color.red;
                }
                if (GUILayout.Button(new GUIContent("拾取坐标")))
                {
                    LevelServiceBlackboard.Instance.SwitchPick(property);
                }
                GUI.color = Color.white;
            }
        }

        private void InitializeValueDict(LevelServiceEditorCustomPropertyAttribute attribute, SerializedProperty property)
        {
            // 记录条件值
            if (!string.IsNullOrEmpty(attribute.conditionFieldName))
            {
                var rConditionFieldPath = property.propertyPath.Replace("." + property.name, "." + this.customAttr.conditionFieldName);
                SerializedProperty conditionProperty = property.serializedObject.FindProperty(rConditionFieldPath);
                if (conditionProperty.propertyType == SerializedPropertyType.ObjectReference)
                {
                    this.customAttrCond = conditionProperty.objectReferenceValue;
                }
                else if (conditionProperty.propertyType == SerializedPropertyType.Integer)
                {
                    this.customAttrCond = conditionProperty.intValue;
                }
            }


            // if (this.showToLong.Count <= 0 && this.showStr.Count <= 0)
            {
                // this.showToLong.Clear();
                this.showToValue.Clear();
                this.showStr.Clear();

                var rConfig = LevelServiceEditorSettingGlobal.GetConfig(attribute.key);
                if (rConfig == null)
                {
                    return;
                }
                if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.CustomInt) > 0)
                {
                    foreach (var rPair in rConfig.value)
                    {
                        var rStr = rPair.Value;
                        this.showToValue.Add(rStr, rPair.Key);
                        this.showStr.Add(rStr);
                    }
                }
                if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.TableID) > 0)
                {
                    if (string.IsNullOrEmpty(rConfig.tableName))
                    {
                        return;
                    }
                    var rTableType = typeof(TableCenter);
                    var rTableProperty = this.GetProperty(rTableType, rConfig.tableName);
                    if (rTableProperty == null)
                    {
                        // LogGame.LogError("未找到配置表" + rConfig.tableName);
                        return;
                    }
                    var rTable = rTableProperty.GetValue(null);
                    if (rTable == null)
                    {
                        this.LoadTable().Forget();
                    }
                    else
                    {
                        var rList = this.GetProperty(rTable.GetType(), "DataList")?.GetValue(rTable) as IReadOnlyList<object>;
                        for (int i = 0; i < rList.Count; i++)
                        {
                            var rObj = rList[i];
                            var rObjType = rObj.GetType();
                            var nID = (int)this.GetProperty(rObjType, "Id").GetValue(rObj);
                            var rShow = nID.ToString();
                            var rDesc = this.GetProperty(rObjType, "Remark");
                            if (rDesc == null)
                            {
                                rDesc = this.GetProperty(rObjType, "Name");
                            }
                            if (rDesc != null)
                            {
                                rShow += $":{rDesc.GetValue(rObj)}";
                            }
                            if (!string.IsNullOrEmpty(rConfig.tableProperty))
                            {
                                var rProperty = this.GetProperty(rObjType, rConfig.tableProperty);
                                if (rProperty != null)
                                {
                                    var rPropertyValue = rProperty.GetValue(rObj);
                                    rShow += $"【{rPropertyValue}】";
                                    this.showToValue.TryAdd(rShow, rPropertyValue);
                                }
                            }
                            else
                            {
                                this.showToValue.TryAdd(rShow, nID);
                            }
                            this.showStr.Add(rShow);
                        }
                    }
                }
                if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.PickCoordinate) > 0)
                {
                    this.pickBtn = true;
                }
                if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.CustomStr) > 0)
                {
                    this.showStr.AddRange(rConfig.valueStr);
                }
                if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.GraphToServiceGroup) > 0)
                {
                    if (this.customAttrCond != null)
                    {
                        var rAsset = this.customAttrCond as BaseGraph;
                        var rPath = AssetDatabase.GetAssetPath(rAsset);
                        var rGroups = LevelServiceBlackboard.Instance.GetPathGroup(rPath);
                        for (int i = 0; i < rGroups?.Count; i++)
                        {
                            var nID = rGroups[i];
                            var rKey = nID.ToString();
                            this.showToValue.Add(rKey, nID);
                            this.showStr.Add(rKey);
                        }
                    }
                }
                if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.ServiceToUnitIndex) > 0)
                {
                    if (this.customAttrCond != null)
                    {
                        var rService = LevelServiceBlackboard.Instance.GetService((int)this.customAttrCond);
                        if (rService != null)
                        {
                            for (int i = 0; i < rService.serviceUnits.Count; i++)
                            {
                                var rKey = i + ":" + rService.serviceUnits[i].name;
                                this.showToValue.Add(rKey, i);
                                this.showStr.Add(rKey);
                            }
                        }
                    }
                }
                if ((rConfig.type & LevelServiceEditorSetting.ELevelServiceEditorConfigType.ExecutionGroup) > 0)
                {
                    var rList = LevelServiceBlackboard.Instance.allExectuionGroupID;
                    if (rList != null)
                    {
                        this.showStr.AddRange(rList);
                    }
                }
            }
        }

        private string GetValueName(long value)
        {
            foreach (var rPair in this.showToValue)
            {
                if (rPair.Value is long && (long)rPair.Value == value)
                {
                    return rPair.Key;
                }
                if (rPair.Value is int && (int)rPair.Value == value)
                {
                    return rPair.Key;
                }
            }
            return value.ToString();
        }

        private async UniTaskVoid LoadTable()
        {
            if (this.tableInitialing)
            {
                return;
            }
            this.tableInitialing = true;
            await TableCenter.LoadTables();
            this.tableInitialing = false;
        }

        private PropertyInfo GetProperty(Type rType, string rName)
        {
            var rProperties = rType.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
            for (int i = 0; i < rProperties.Length; i++)
            {
                if (rProperties[i].Name.ToLower() == rName.ToLower())
                {
                    return rProperties[i];
                }
            }
            return null;
        }
    }

    public class LevelServiceEditorCustomPropertyAttribute : PropertyAttribute
    {
        public LevelServiceEditorCustomPropertyAttribute(string displayName)
        {
            this.displayName = displayName;
            this.prefix = "Common";
            this.key = this.prefix + "_" + this.displayName;
        }

        public LevelServiceEditorCustomPropertyAttribute(ServiceExecutionType executionType, string displayName, string conditionFieldName = "")
        {
            this.displayName = displayName;
            this.prefix = "Ex_";
            this.conditionFieldName = conditionFieldName;
            this.key = this.prefix + ((int)executionType).ToString("D2") + "_" + this.displayName;
        }

        public LevelServiceEditorCustomPropertyAttribute(ServiceTriggerType triggerType, string displayName)
        {
            this.displayName = displayName;
            this.prefix = "Tr_";
            this.key = this.prefix + ((int)triggerType).ToString("D2") + "_" + displayName;
        }

        public LevelServiceEditorCustomPropertyAttribute(string prefix, string displayName)
        {
            this.prefix = prefix;
            this.displayName = displayName;
            this.key = this.prefix + "_" + this.displayName;
        }

        public LevelServiceEditorCustomPropertyAttribute(string prefix, string displayName, string conditionFieldName)
        {
            this.displayName = displayName;
            this.prefix = prefix;
            this.key = this.prefix + "_" + this.displayName;
            this.conditionFieldName = conditionFieldName;
        }

        public string prefix;
        public string key;
        public string displayName;
        public string conditionFieldName;
        // public object conditionValue;
    }
}